package com.power;

import com.power.common.PowerConstant;
import com.power.electric.*;
import com.power.service.ElectricPowerService;
import com.power.util.SpringContextUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author Lijunxiong
 */
@Service
@Slf4j
public class ElectricPower {

    private final StringCliParameter hostParam = new CliParameterBuilder("-h")
            .setDescription("The IP/domain address of the server you want to access.").setMandatory()
            .buildStringParameter("host");
    private final IntCliParameter portParam = new CliParameterBuilder("-p").setDescription("The port to connect to.")
            .buildIntParameter("port", 2406);
    private volatile Connection connection;
    int commonAddress = 1;
    private int acknowledgedReceiveSequenceNumber = 0;
    private int sendSequenceNumber = 0;
    private int receiveSequenceNumber = 0;
    private int acknowledgedSendSequenceNumber = 0;
    private final ScheduledExecutorService maxTimeNoAckSentTimer = Executors.newSingleThreadScheduledExecutor();
    private ScheduledFuture<?> maxTimeNoAckSentFuture = null;
    private ScheduledFuture<?> maxTimeNoAckReceivedFuture = null;
    private final byte[] buffer = new byte[255];
    private ConnectionSettings settings;
    private final DataInputStream is = null;
    private String powerToHighAndLows =null;

    /**
     * 获取电力数据
     * @param powerIp
     * @param powerToHighAndLow
     * @throws IOException
     */
    public void connect(String powerIp,String powerToHighAndLow) throws IOException {
        System.out.println("powerIp"+powerIp);
        System.out.println("powerToHighAndLow"+powerToHighAndLow);
        log.info("开始采集"+powerToHighAndLow+"压数据");
        //赋值
        powerToHighAndLows = powerToHighAndLow;

        //创建连接
        try {
            InetAddress address;
            address = InetAddress.getByName(powerIp);
            ClientConnectionBuilder clientConnectionBuilder = new ClientConnectionBuilder(address).setPort(2406);
            connection = clientConnectionBuilder.connect();
            connection.startDataTransfer(new ElectricPower.ClientEventListener(), 5000);
            log.info(powerToHighAndLow+"创建连接成功");
        } catch (TimeoutException ex) {
            Logger.getLogger(ElectricPower.class.getName()).log(Level.SEVERE, null, ex);
            log.error("创建连接失败"+ex);
        }

        //总召和校时后，遥测（电压和电流）和遥信（开关位）数据就会传送过来
        //电度（用电量）数据需要单独召唤
        //发送总召
        // 68 0E 00 00（发送序号）00 00（接收序号）64（类型标示）01（可变结构限定词）06 00（传输原因）01 00（公共地址即RTU地址）00
        // 00 00（信息体地址）14
        try {
            connection.interrogation(commonAddress, CauseOfTransmission.ACTIVATION, new IeQualifierOfInterrogation(20));
            log.info(powerToHighAndLow+"发送总召成功");
        } catch (IOException ex) {
            Logger.getLogger(ElectricPower.class.getName()).log(Level.SEVERE, null, ex);
            log.error("发送总召失败"+ex);
        }

        //校时
        try {
            connection.synchronizeClocks(commonAddress, new IeTime56(System.currentTimeMillis()));
            log.info(powerToHighAndLow+"校时成功");
        }catch (IOException ex){
            log.error("校时失败"+ex);
        }

        //召唤电度数据
        try {
            connection.counterInterrogation(commonAddress, CauseOfTransmission.ACTIVATION,
                    new IeQualifierOfCounterInterrogation(20, 10));
            log.info(powerToHighAndLow+"召唤电度数据成功");
        } catch (IOException ex) {
            Logger.getLogger(ElectricPower.class.getName()).log(Level.SEVERE, null, ex);
            log.error("召唤电度数据"+ex);
        }
    }

    public class ClientEventListener implements ConnectionEventListener {
        private ElectricPowerService electricPowerService;

        @Override
        public void newASdu(ASdu aSdu)  {

            this.electricPowerService = SpringContextUtil.getBean(ElectricPowerService.class);
            TypeId typeId = aSdu.getTypeIdentification();
            switch (typeId) {
                //总召信息
                case C_IC_NA_1:
                    break;
                //总召电度信息
                case C_CI_NA_1:
                    break;
                //遥信数据
                case M_SP_NA_1:
                    processMeasuredValue(aSdu,powerToHighAndLows,PowerConstant.POWER_SINGLEPOINT);
                    break;
                //遥测数据
                case M_ME_NC_1:
                    processMeasuredValue(aSdu,powerToHighAndLows,PowerConstant.POWER_REMOTEDETECT);
                    break;
                //电度数据
                case M_IT_NA_1:
                    processMeasuredValue(aSdu,powerToHighAndLows,PowerConstant.POWER_PROCESS);
                    break;
                default:
                    break;
            }
        }

        @Override
        public void connectionClosed(IOException e) {
            //throw new UnsupportedOperationException("Not supported yet."); // To change body of generated methods,
            connection.close();
        }

        //电力数据解析存储
        public void processMeasuredValue(ASdu aSdu,String powerToHighAndLows,String dataType) {
            InformationObject[] informationObjects = aSdu.getInformationObjects();
            for (InformationObject informationObject : informationObjects) {
                int addr = informationObject.getInformationObjectAddress();
                InformationElement[][] informationElementses = informationObject.getInformationElements();
                for (int i = 0; i < informationElementses.length; i++) {
                    //遥测数据存储redis
                    if(PowerConstant.POWER_REMOTEDETECT.equals(dataType)){
                        IeShortFloat shortFloat = (IeShortFloat) informationElementses[i][0];
                        electricPowerService.addPowerToRedis(String.valueOf(addr + i),String.valueOf(shortFloat.getValue()),powerToHighAndLows,dataType);
                    //遥信数据存储redis
                    }else if(PowerConstant.POWER_SINGLEPOINT.equals(dataType)){
                        IeSinglePointWithQuality singlePointWithQuality = (IeSinglePointWithQuality) informationElementses[i][0];
                        electricPowerService.addPowerToRedis(String.valueOf(addr + i),String.valueOf((singlePointWithQuality.isOn() ? 1 : 0)),powerToHighAndLows,dataType);
                    //电度数据存储redis
                    }else if(PowerConstant.POWER_PROCESS.equals(dataType)){
                        IeBinaryCounterReading ieBinaryCounterReading = (IeBinaryCounterReading) informationElementses[i][0];
                        electricPowerService.addPowerToRedis(String.valueOf(addr + i),String.valueOf(ieBinaryCounterReading.getCounterReading()),powerToHighAndLows,dataType);
                    }
                }
            }
        }
    }
}
